#include "RMTNew.h"






RxTaskClass* taskClass[RMT_MAX_CHANNELS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};

rmt_obj_t* RMTNewClass::txInit(int pin, float tick, uint8_t blockNum)
{
	rmt_obj_t* rmt_send = rmtInit(pin, RMT_TX_MODE, RMT_MEM_64);
	if(rmt_send == NULL){
		Serial.println("ERROR");
		return NULL;
	}
	rmtSetTick(rmt_send, tick);
	return rmt_send;
}

rmt_obj_t* RMTNewClass::rxInit(int pin, float tick, uint32_t timeOut, uint8_t blockNum, RMTRxCallback1 receive_cb, void * const parameters)
{
	rmt_obj_t* rmt_receive = rmtInit(pin, RMT_RX_MODE, (rmt_reserve_memsize_t)blockNum);
	if(rmt_receive == NULL){
		Serial.println("ERROR");
		return NULL;
	}
	float realTick = rmtSetTick(rmt_receive, tick);
	rmtRead(rmt_receive, receive_cb, parameters);
	return rmt_receive;
}

uint32_t RMTNewClass::rxStart(RmtChannel ch, RMTRxCallback rxCb, void * const parameters)
{
	if (RMTObj[ch].handleRxTask == NULL && RMTObj[ch].allocated){
		RMTObj[ch].parameters = parameters;
		char name[] = "RxTaskChannelX";
		name[13] = ch + '0';
		RMTObj[ch].rxCb = rxCb;
		taskClass[ch] = new RxTaskClass(ch);
        xTaskCreatePinnedToCore(taskClass[ch]->RxTaskChannel, name, 8192, taskClass[ch], 2, &RMTObj[ch].handleRxTask, 1);
	}
}

uint8_t RMTNewClass::getClkDiv(float tick){
    int apb_div = RMT_LIMIT(tick/12.5, 256);
    int ref_div = RMT_LIMIT(tick/1000, 256);

    float apb_tick = 12.5 * apb_div;
    float ref_tick = 1000.0 * ref_div;

    if (RMT_ABS(apb_tick - tick) <= RMT_ABS(ref_tick - tick)) {
        return apb_div & 0xFF;
    } else {
        return ref_div & 0xFF;
    }
}

float RMTNewClass::setTick(RmtChannel ch, float tick)
{
    int apb_div = RMT_LIMIT(tick/12.5, 256);
    int ref_div = RMT_LIMIT(tick/1000, 256);

    float apb_tick = 12.5 * apb_div;
    float ref_tick = 1000.0 * ref_div;

    if (RMT_ABS(apb_tick - tick) < RMT_ABS(ref_tick - tick)) {
        rmt_set_clk_div((rmt_channel_t)ch, apb_div & 0xFF);
        return apb_tick;
    } else {
        rmt_set_clk_div((rmt_channel_t)ch, ref_div & 0xFF);
        return ref_tick;
    }
}

uint32_t RMTNewClass::rxStop(RmtChannel ch)
{
	if (RMTObj[ch].handleRxTask){
	    vTaskDelete(RMTObj[ch].handleRxTask);
		RMTObj[ch].handleRxTask = NULL;
		RMTObj[ch].rxCb = NULL;
		RMTObj[ch].parameters = NULL;
		delete taskClass[ch];
	}
}

void RMTNewClass::rxDeinit(RmtChannel ch)
{
    if (ch < RMT_CHANNEL_MAX) {
		if (RMTObj[ch].handleRxTask)
			rxStop(ch);
		rmt_driver_uninstall((rmt_channel_t)ch);
		//gpio_matrix_in(0x30, RMT_SIG_IN0_IDX + ch, false);
		pinMode(RMTObj[ch].pin, INPUT);
		RMTObj[ch].pin = -1;
		RMTObj[ch].allocated = false;
		RMTObj[ch].mode = RMT_MODE_MAX;
	}
}

void RMTNewClass::txDeinit(rmt_obj_t* ch)
{
    rmtDeinit(ch);
}

bool RMTNewClass::write(RmtChannel ch, rmt_item32_t* data, size_t size)
{
    ESP_ERROR_CHECK(rmt_write_items((rmt_channel_t)ch, data, size, false));
}

bool RMTNewClass::writeAsync(rmt_obj_t* ch, rmt_data_t* data, size_t size)
{
    return rmtWrite(ch, data, size);
}

RmtChannel RMTNewClass::getChannel(int pin)
{
	for (int i=0; i<RMT_MAX_CHANNELS; i++) {
		if(RMTObj[i].allocated && RMTObj[i].pin == pin)
		{
			return RMTObj[i].channel;
		}
	}
	for (int i=0; i<RMT_MAX_CHANNELS; i++) {
		if(!RMTObj[i].allocated)
		{
			RMTObj[i].pin = pin;
			RMTObj[i].allocated = true;
			return RMTObj[i].channel;
		}
	}
}

RMTNewClass::RMTNewClass() {
	
}
RMTNewClass::~RMTNewClass(){}

RMTNewClass RmtNew;

